﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using TinyERP.Framework;
using System.Text.RegularExpressions;

namespace TinyERP.Framework.Validation
{
    public class ValidationError
    {
        public string ErrorMessage { get; set; }
        public IValidationRule ValidationRule { get; set; }
        public ValidationError(string errorMessage, IValidationRule rule)
        {
            this.ErrorMessage = errorMessage;
            this.ValidationRule = rule;
        }
    }
    public interface IValidationRule
    {
        ValidationError Validate();
        Control ControlToValidate { get; set; }
    }
    public abstract class AbstractValidationRule: IValidationRule
    {
        protected string errorMessagePattern;
        protected string fieldName;
        public Control ControlToValidate { get; set; }
        public AbstractValidationRule(Control controlToValidate, string fieldName)
        {
            this.fieldName = fieldName;
            this.ControlToValidate = controlToValidate;
        }
        public AbstractValidationRule(Control controlToValidate, string fieldName, string errorMessagePattern)
        {
            this.ControlToValidate = controlToValidate;
            this.fieldName = fieldName;
            this.errorMessagePattern = errorMessagePattern;
        }
       
        public abstract ValidationError Validate();
    }
    public class PatternMatchedRule : AbstractValidationRule
    {
        public string RegularExpression { get; set; }
        public PatternMatchedRule(Control controlToValidate, string fieldName, string regularExp)
            : base(controlToValidate, fieldName)
        {
            errorMessagePattern = AppResourceManager.GetInstance().GetString("MsgInvalidFormat");
            this.RegularExpression = regularExp;
        }

        public override ValidationError Validate()
        {
            Regex regEx = new Regex(RegularExpression, RegexOptions.IgnoreCase);
            if (!regEx.IsMatch(ControlToValidate.Text))
            {
                string errorMessage = string.Format(errorMessagePattern, fieldName);
                return new ValidationError(errorMessage, this);
            }
            return null;
        }
    }
    
    public class EmailRule : PatternMatchedRule
    {
        public EmailRule(Control controlToValidate, string fieldName)
            : base(controlToValidate, fieldName, "")
        {
            errorMessagePattern = AppResourceManager.GetInstance().GetString("MsgInvalidFormat");
            this.RegularExpression = @"^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$";
        }
    }

    public class RequiredFieldRule : AbstractValidationRule
    {
        public RequiredFieldRule(Control controlToValidate, string fieldName)
            : base(controlToValidate, fieldName)
        {
            errorMessagePattern = AppResourceManager.GetInstance().GetString("MsgRequiredField");
        }
        
        public override ValidationError Validate()
        {
            if(string.IsNullOrEmpty(this.ControlToValidate.Text.Trim())) 
            {
                string errorMessage = string.Format(errorMessagePattern, fieldName);
                return new ValidationError(errorMessage, this);
            }
            return null;
        }
    }

    public class CompareFieldRule : AbstractValidationRule
    {
        private Control compareControl;
        private string fieldNameToCompare;
        public CompareFieldRule(Control controlToValidate, Control compareControl, string fieldName, string fieldNameToCompare)
            : base(controlToValidate, fieldName)
        {
            this.compareControl = compareControl;
            this.fieldNameToCompare = fieldNameToCompare;
            errorMessagePattern = AppResourceManager.GetInstance().GetString("MsgInvalidCompare");
        }

        public override ValidationError Validate()
        {
            if (string.IsNullOrEmpty(this.ControlToValidate.Text.Trim()))
            {
                string errorMessage = string.Format(errorMessagePattern, fieldName, fieldNameToCompare);
                return new ValidationError(errorMessage, this);
            }
            return null;
        }
    }
    public class Validator
    {
        private ErrorProvider errorProvider;
        IList<IValidationRule> validationRules;
        public Validator()
        {
            errorProvider = new ErrorProvider();
            validationRules = new List<IValidationRule>();
        }
        public void AddValidationRule(IValidationRule rule)
        {
            validationRules.Add(rule);
        }
        public bool Validate()
        {
            bool isValid = true;
            errorProvider.Clear();
            foreach (IValidationRule rule in validationRules)
            {
                ValidationError error = rule.Validate();
                if (error != null)
                {
                    //focus on first input field
                    if (isValid)
                    {
                        isValid = false;
                        rule.ControlToValidate.Focus();
                    }
                    errorProvider.SetError(rule.ControlToValidate, error.ErrorMessage);
                }
            }
            return isValid;
        }
    }
}
